#ifndef CUBICWINDOW_H
#define CUBICWINDOW_H

/**
 * Klasa reprezentuje polozenie przestrzennego okna w obrazie.
 */
class CubicWindow{
    /**
     * Okresla dokladnsc maski (ilosc czesci dzielacych piksel)
     */
    int maskStep;
    /**
     * Wskaznik na dane obrazu
     */
    unsigned int*** data;
    /**
     * Maksymalny rozmiar x danych
     */
    int maxX;
    /**
     * Maksymalny rozmiar y danych
     */
    int maxY;
    /**
     * Maksymalny rozmiar z danych
     */
    int maxZ;
    /**
     * Aktualne polozenie okna. wspolrzedna x
     */
    int x;
    /**
     * Aktualne polozenie okna. wspolrzedna y
     */
    int y;
    /**
     * Aktualne polozenie okna. wspolrzedna z
     */
    int z;
    /**
     * Szerokosc okna. wspolrzedna x
     */
    int _x;
    /**
     * Szerokosc okna. wspolrzedna y
     */
    int _y;
    /**
     * Szerokosc okna. wspolrzedna z
     */
    int _z;
    /**
     * Maska waznosci pikseli w oknie
     */
    float *** mask;
    /**
     * Konstruktor domyslny
     * @param X Maksymalny rozmiar danych w osi x
     * @param Y Maksymalny rozmiar danych w osi y
     * @param Z Maksymalny rozmiar danych w osi z
     * @param data Wskaznika na dane
     */
    public: CubicWindow(int X, int Y, int Z, unsigned int*** data){
        this->maxX = X;
        this->maxY = Y; 
        this->maxZ = Z;
        this->data = data;
        mask = NULL;
        maskStep = 20;
    }
    /**
     * Ustawia punkt okna i jego rozmiary
     * @param _x Polozenie okna w osi x (numer piksela)
     * @param _y Polozenie okna w osi y (numer piksela)
     * @param _z Polozenie okna w osi z (numer piksela)
     * @param r_x Szerokosc okna w osi x (ilosc pikseli)
     * @param r_y Szerokosc okna w osi y (ilosc pikseli)
     * @param r_z Szerokosc okna w osi z (ilosc pixeli)
     * @return Zwraca 0 przy sukcesie, 1 w przypadku nieprawidlowych danych.
     */
    int setWindow(int _x, int _y, int _z, int r_x, int r_y, int r_z){
        if(_x < 0 || _y < 0 || _z < 0  || r_x < 0 || r_y < 0 || r_z < 0)
            return 1;
        if(_x+r_x > maxX-1 || _y+r_y > maxY-1 || _z+r_z > maxZ-1)
            return 1;
        //mask[z][y][z]
        if(mask != NULL){
            for(int k=0;k<r_z;k++){
                for(int j=0;j<r_y;j++){
                    delete [] mask[k][j];    
                }
                delete [] mask[k];
            }
            delete [] mask;
            mask=NULL;
        }
        this->x = _x;
        this->y = _y; 
        this->z = _z;
        this->_x = r_x;
        this->_y = r_y; 
        this->_z = r_z;
        //obliczenie maski
        mask = new float**[r_z];
        for(int k=0;k<r_z;k++){
            mask[k] = new float*[r_y];
            for(int j=0;j<r_y;j++){
                mask[k][j] = new float[r_x];
                for(int i=0;i<r_x;i++)
                    mask[k][j][i]=0.0;
            }
        }
        for(int k=0; k<(r_z)*maskStep; k++){
            for(int j=0; j<(r_y)*maskStep; j++){
                for(int i=0; i<(r_x)*maskStep; i++){
                    if(pow(i-r_x*maskStep/2.0,2)+
                    pow(j-r_y*maskStep/2.0,2)+
                    pow(k-r_z*maskStep/2.0,2) <= 1.0)
                        mask[k/maskStep][j/maskStep][i/maskStep]+=1.0/pow(maskStep,3);
                }
            }
        }
        return 0;
    }
    /**
     * Oblicza moment geometryczny podanego rzedu
     * @param p Rzad p momentu
     * @param q Rzad q momentu
     * @param r Rzad r momentu
     * @return Zwraca wartosc momontu geometrycznego o podanym rzedzie
     */
    double getMoment(int p, int q, int r){
        double moment = 0.0;
        for(int i=x; i<=x+_x; i++){
            for(int j=y; j<=y+_y; j++){
                for(int k=z; k<=z+_z; k++){
                    moment+=pow(i,p)*pow(j,q)*pow(k,r)*data[k][j][i]*mask[k-z][j-y][i-x];
                }
            }
        }
        return moment;
    }
    
};

#endif // CUBICWINDOW_H
